Skip to content

feat: install plugins to auto-load across sessions (#36) - #227

Merged
matheuswhite merged 1 commit into
mainfrom
feat/36-install-plugin
Jul 24, 2026
Merged

feat: install plugins to auto-load across sessions (#36)#227
matheuswhite merged 1 commit into
mainfrom
feat/36-install-plugin

Conversation

@matheuswhite

Copy link
Copy Markdown
Owner

What

Closes #36. Adds !plugin install <file>: it loads the plugin and records it so every subsequent Scope session auto-loads it at start-up — no more re-running !plugin load for your everyday plugins. !plugin list prints the installed set.

!plugin install analytics.lua   # load now + persist
!plugin list                    # -> Installed plugins: analytics

How

  • src/plugin/installed.rs (new) — the manifest Installed over <config_dir>/scope/plugins/installed.toml (plugins = ["name", …]), next to the staged .lua files. load/names/contains/add (dedup) / save, dir-injected and unit-tested. It is program-managed state (not the user's config.toml): a missing manifest means "nothing installed", and a malformed one is logged and skipped so it can never brick start-up.
  • src/plugin/engine.rsPluginEngineCommand::{InstallPlugin, ListInstalledPlugins}. Install stages + loads the plugin and persists only after a successful load (a plugin that fails to load is never added to the auto-load set), deduping so re-installs are idempotent. load_installed_plugins runs once at the top of task_async, before the command loop, auto-loading each installed plugin from its staged copy and logging per plugin like !plugin load; a broken/missing entry is logged and skipped.
  • src/inputs/inputs_task.rs — the !plugin handler is refactored to a subcommand-first shape so list needs no argument while load/reload/install/unload each take one; the existing load/reload/unload behavior is preserved.
  • Docs: README command table + Plugins section, plugins/README.md, CLAUDE.md.

Uninstall is deliberately out of scope — it is issue #37. The manifest already supports removal for that follow-up.

Tests

  • installed.rs unit tests: missing / malformed / round-trip / dedup / dir-creation.
  • tests/tui_e2e.rs (harness gained a StartOpts builder + a plugins_dir() accessor):
    • install persists to the manifest;
    • a manifest entry auto-loads at start-up;
    • a failed install does not persist (safety);
    • a malformed manifest at start-up is non-fatal (app still reaches ready, error logged);
    • !plugin list reports the empty and populated sets;
    • installing a reserved name (scope/shell) is rejected and not persisted.

The last four were added from an adversarial review of the diff, which found no logic defects — only these coverage gaps on the safety paths.

All 231 unit + 20 e2e tests pass (1 e2e ignored on macOS per the existing PTY-baud limitation); tree is warning-clean under #![deny(warnings)].

🤖 Generated with Claude Code

Add `!plugin install <file>`, which loads a plugin and records its name in a
persistent manifest (`<config_dir>/scope/plugins/installed.toml`) so every
subsequent session auto-loads it at start-up; `!plugin list` prints the
installed set.

A new `plugin/installed.rs` owns the manifest (load/add/save, dir-injected and
unit-tested); it is program-managed state, so a missing manifest is simply
"nothing installed" and a malformed one is logged and skipped rather than
bricking the app. The engine grows `PluginEngineCommand::{InstallPlugin,
ListInstalledPlugins}`: install stages+loads the plugin and persists it only
after a successful load (a broken plugin is never recorded), deduping so
re-installs are idempotent. `load_installed_plugins` runs once at the top of
`task_async`, before the command loop, auto-loading each installed plugin from
its staged copy and logging per plugin like `!plugin load`. The `!plugin`
command handler is refactored to a subcommand-first shape so `list` needs no
argument while load/reload/install/unload each take one.

Uninstall is issue #37.

Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
@matheuswhite
matheuswhite merged commit 756643c into main Jul 24, 2026
8 checks passed
@matheuswhite
matheuswhite deleted the feat/36-install-plugin branch July 24, 2026 18:32
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Add a command to install a plugin

1 participant